from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Header, Form
from fastapi.security import OAuth2PasswordRequestForm
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from datetime import datetime, timedelta
import random
import httpx
from config import DX_API_URL
from fastapi_users.jwt import generate_jwt

from app.models.db import User, get_async_session, SmsCode, Role, UserRole
from app.models.user import get_user_manager, auth_backend, UserManager, current_active_user, fastapi_users, SECRET
from app.utils.auth import get_user_role_codes
from app.schemas.schemas import UserCreate  # 导入UserCreate模型

router = APIRouter(prefix="/auth", tags=["auth"])


class Token(BaseModel):
    access_token: str
    token_type: str
    

class LoginResponse(BaseModel):
    access_token: str
    token_type: str
    user: Dict[str, Any]
    roles: str


class RefreshTokenResponse(BaseModel):
    access_token: str
    token_type: str


class UserRolesResponse(BaseModel):
    user_id: str
    roles: str


class SmsCodeRequest(BaseModel):
    phone: str


class SmsCodeVerifyRequest(BaseModel):
    phone: str
    code: str


@router.post("/login", response_model=LoginResponse)
async def login(
    credentials: OAuth2PasswordRequestForm = Depends(),
    user_manager: UserManager = Depends(get_user_manager),
    session: AsyncSession = Depends(get_async_session),
):
    """
    自定义登录接口，支持用户名登录
    """
    user = await user_manager.authenticate(credentials)
    
    if user is None or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户名或密码错误",
        )
    
    # 更新最后登录时间
    user.last_login_time = datetime.now()
    session.add(user)
    await session.commit()
    
    # 生成token - 使用auth_backend的login方法
    strategy = auth_backend.get_strategy()
    response = await auth_backend.login(strategy, user)
    
    # 解析响应内容
    token_data = response.body.decode()
    import json
    token_info = json.loads(token_data)
    
    # 构建用户信息
    user_data = user.dict()
    
    return {
        "access_token": token_info["access_token"],
        "token_type": token_info["token_type"],
        "user": user_data,
        "roles": await get_user_role_codes(str(user.id), session)
    }


@router.post("/refresh", response_model=RefreshTokenResponse)
async def refresh_token(
    authorization: str = Header(..., description="Bearer token"),
    user: User = Depends(current_active_user),
):
    """
    刷新访问令牌
    
    使用当前有效的访问令牌获取新的访问令牌，以延长会话有效期。
    前端应在token即将过期前调用此接口获取新token。
    
    Args:
        authorization: 格式为"Bearer your_token"的授权头
        user: 当前认证用户
        
    Returns:
        新的访问令牌
    """
    try:
        # 验证Authorization头格式
        if not authorization.startswith("Bearer "):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED, 
                detail="无效的授权头格式"
            )
        
        # 使用auth_backend的login方法生成新token
        strategy = auth_backend.get_strategy()
        response = await auth_backend.login(strategy, user)
        
        # 解析响应内容
        token_data = response.body.decode()
        import json
        token_info = json.loads(token_data)
        
        return {
            "access_token": token_info["access_token"],
            "token_type": token_info["token_type"]
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"刷新令牌失败: {str(e)}"
        )


@router.get("/roles", response_model=UserRolesResponse)
async def get_user_roles(
    current_user: User = Depends(current_active_user),
    session: AsyncSession = Depends(get_async_session)
):
    """
    获取当前登录用户的角色代码(多个角色用逗号分隔)
    """
    user_id = str(current_user.id)
    roles = await get_user_role_codes(user_id, session)
    
    return {
        "user_id": user_id,
        "roles": roles
    }

@router.post("/send-sms-code")
async def send_sms_code(
    phone: str = Form(...),
    session: AsyncSession = Depends(get_async_session)
):
    """
    发送短信验证码
    
    Args:
        phone: 手机号
        
    Returns:
        发送结果
    """
    try:
        # 检查手机号格式(简单校验)
        if not phone or len(phone) != 11:
            raise HTTPException(status_code=400, detail="无效的手机号码")
        
        # 生成4位数字验证码
        code = ''.join(random.choices('0123456789', k=4))
        
        # 检查是否已有该手机号的验证码记录
        query = select(SmsCode).where(SmsCode.phone == phone)
        result = await session.execute(query)
        existing_code = result.scalar_one_or_none()
        
        if existing_code:
            # 如果存在，则更新验证码和过期时间
            existing_code.code = code
            existing_code.expired_at = datetime.now() + timedelta(minutes=5)
            session.add(existing_code)
        else:
            # 否则创建新记录
            new_code = SmsCode(
                phone=phone,
                code=code
            )
            session.add(new_code)
        
        await session.commit()
        
    
        sms_url = DX_API_URL+"/"+phone+"/"+code
        
        # 发送GET请求到短信API
        async with httpx.AsyncClient() as client:
            response = await client.get(sms_url)
            if response.status_code != 200:
                # 记录错误但不返回给前端
                print(f"短信API调用失败: {response.status_code} - {response.text}")
        
        # 返回结果
        return {
            "message": "验证码发送成功"
        }
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=500, detail=f"发送验证码失败: {str(e)}")

@router.post("/sms-login", response_model=None)
async def sms_login(
    phone: str = Form(...),
    code: str = Form(...),
    user_manager: UserManager = Depends(get_user_manager),
    session: AsyncSession = Depends(get_async_session)
):
    """
    短信验证码登录/注册
    
    如果验证码正确，检查用户是否存在：
    - 存在则直接登录
    - 不存在则以手机号作为用户名注册新用户并登录
    
    Args:
        phone: 手机号
        code: 验证码
        
    Returns:
        登录信息，包含token和用户信息
    """
    try:
        # 验证短信验证码
        sms_query = select(SmsCode).where(
            SmsCode.phone == phone,
            SmsCode.code == code,
            SmsCode.expired_at > datetime.now()
        )
        sms_result = await session.execute(sms_query)
        sms_code = sms_result.scalar_one_or_none()
        
        if not sms_code:
            raise HTTPException(status_code=400, detail="验证码无效或已过期")
        
        # 验证成功后删除验证码
        await session.delete(sms_code)
        
        # 查询手机号对应的用户
        user_query = select(User).where(User.phone == phone)
        user_result = await session.execute(user_query)
        user = user_result.scalar_one_or_none()
        
        if not user:
            # 用户不存在，创建新用户
            # 生成随机密码（用户无需记住，因为使用短信验证码登录）
            password = ''.join(random.choices('0123456789abcdefghijklmnopqrstuvwxyz', k=10))
            
            # 使用UserCreate模型创建用户
            user_data = UserCreate(
                username=phone,  # 使用手机号作为用户名
                email=f"{phone}@datatk.com",
                nickname=phone,
                password=password,
                phone=phone,
                status=1,
                is_active=True,
                is_verified=True,
                is_superuser=False
            )
            
            user = await user_manager.create(user_data)
            
            # 为新用户分配默认角色（普通用户或一般用户）
            default_role_query = select(Role).where(
                Role.name.in_(["普通用户", "一般用户"])
            )
            default_role_result = await session.execute(default_role_query)
            default_role = default_role_result.scalar_one_or_none()
            
            if default_role:
                # 创建用户角色关联
                user_role = UserRole(
                    user_id=str(user.id),
                    role_id=default_role.id,
                    created_at=datetime.now()
                )
                session.add(user_role)
        
        # 更新最后登录时间
        user.last_login_time = datetime.now()
        session.add(user)
        
        await session.commit()
        
        # 生成token
        strategy = auth_backend.get_strategy()
        response = await auth_backend.login(strategy, user)
        
        # 解析响应内容
        token_data = response.body.decode()
        import json
        token_info = json.loads(token_data)
        
        # 构建用户信息
        user_data = user.dict()
        
        # 获取用户角色
        user_roles = await get_user_role_codes(str(user.id), session)
        
        return {
            "access_token": token_info["access_token"],
            "token_type": token_info["token_type"],
            "username": user_data["username"],
            "roles": user_roles
        }
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=500, detail=f"短信登录失败: {str(e)}") 